package com.btb.core.schedule;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class Executor {

	private static final int SIZE = 6;
	private final List<Job> jobList = new ArrayList<>();
	private final String name;
	private ThreadPoolExecutor pool;

	public Executor(final String name, int size) {
		this.name = name;
		this.pool = new ThreadPoolExecutor(size, size, 0L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(),
				new MatchThreadFactory());
	}

	public void execute(final Job r) {
		this.pool.execute(r);
		this.jobList.add(r);
	}

	/**
	 * 确保关闭线程池
	 *
	 * @param pool
	 */
	public static void ensureShutdown(final ThreadPoolExecutor pool) {
		pool.shutdownNow();
		try {
			while (!pool.awaitTermination(100, TimeUnit.MILLISECONDS)) {
				log.info("still not shutdown");
			}
		} catch (final InterruptedException e) {
			log.error("interrepted", e);
		}
		log.info("shutdown over");
	}

	public void shutdown() {
		this.jobList.forEach(job -> job.shutdown());
		ensureShutdown(this.pool);
	}

	public void rebuild() {
		this.pool = new ThreadPoolExecutor(SIZE, SIZE, 0L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(),
				new MatchThreadFactory());
	}

	/**
	 * The match engine thread factory
	 */
	private class MatchThreadFactory implements ThreadFactory {
		private final ThreadGroup group;
		private final AtomicInteger threadNumber = new AtomicInteger(1);
		private final String namePrefix;

		MatchThreadFactory() {
			final SecurityManager s = System.getSecurityManager();
			this.group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
			this.namePrefix = "mark-" + Executor.this.name + "-thread-";
		}

		@Override
		public Thread newThread(final Runnable r) {
			final Thread t = new Thread(this.group, r, this.namePrefix + this.threadNumber.getAndIncrement(), 0);
			if (t.isDaemon()) {
				t.setDaemon(false);
			}
			if (t.getPriority() != Thread.NORM_PRIORITY) {
				t.setPriority(Thread.NORM_PRIORITY);
			}
			return t;
		}
	}

}